<?php

namespace App\Models\XS;

use DB;
use XSException, XSDocument;
use Illuminate\Pagination\Paginator;

class JobXS extends CmsXS
{
    public function __construct()
    {
        parent::__construct(config_path('xunsearch_job.ini'));
        //model层得判断，传入的id是否为当前用户的职位id,
        //或者批量更新的话，需要判断是否为后台登录的用户

    }

    /**
     * 迅搜职位统计数
     * @return bool|int
     */
    public static function getJobXSTotal()
    {
        try {
            return (new JobXS())->search->dbTotal;
        } catch (XSException $e) {
            return false;
        }
    }

    /**添加一条或多条职位记录
     * @param $id
     * @return bool
     */
    public static function storeJob($id)
    {
        try {
            $xs = new JobXS();
            $id = is_array($id) ? $id : func_get_args();
            $company_job = $xs->getFromMySql($id);
            if (count($company_job) < 1) {
                return false;
            }
            $jobs = $company_job;
            $index = $xs->index;
            $bl = count($jobs) > self::$OPEN_BUFFER_COUNT;
            if ($bl) $index->openBuffer(); // 开启缓冲区
            foreach ($jobs as $key => $value) {
                $doc = new XSDocument();
                $data = $xs->makeData($value);
                $doc->setFields($data); //用数组进行批量赋值
                $index->add($doc);
            }
            if ($bl) $index->closeBuffer();
            return true;
        } catch (XSException $e) {
            return false;
        }
    }

    /**删除一条或多条职位记录
     * @param $id
     * @return bool
     */
    public static function deleteJob($id)
    {
        try {
            if (empty($id)) return false;

            $xs = new JobXS();

            //把id转为数组
            $ids = is_array($id) ? $id : func_get_args();

            $index = $xs->index;

            $xs->logXSDaily('后台手动删除职位---------');
            foreach ($ids as $v) {
                try {
                    $index->del($v);
                    $xs->logXSDaily("id=$v 职位删除成功");
                } catch (XSException $e) {
                    $xs->logXSDaily("id=$v 职位删除失败 - " . $e->getMessage());
                }
            }

            //强制刷新迅搜
            $index->flushIndex();

            return true;
        } catch (XSException $e) {
            return false;
        }
    }

    /** 清空所有职位
     * @return bool
     */
    public static function clean()
    {
        try {
            $xs = new JobXS();
            $xs->index->clean();
            return true;
        } catch (XSException $e) {
            return false;
        }
    }

    /** 更新一条或多条职位记录
     * @param $id
     * @return bool
     */
    public static function updateJob($id)
    {
        try {
            $xs = new JobXS();
            $id = is_array($id) ? $id : func_get_args();
            $company_job = $xs->getFromMySql($id);
            if (count($company_job) < 1) {
                return false;
            }
            $index = $xs->index;
            $jobs = $company_job->toArray();
            $bl = count($jobs) > self::$OPEN_BUFFER_COUNT;
            if ($bl) $index->openBuffer(); // 开启缓冲区
            $doc = new XSDocument();
            foreach ($jobs as $key => $value) {
                $data = $xs->makeData($value);
                $doc->setFields($data); //用数组进行批量赋值
                $index->update($doc);
            }
            if ($bl) $index->closeBuffer(); // 关闭缓冲区
            return true;
        } catch (XSException $e) {
            return false;
        }
    }

    public $cms_total = 0;
    public $cms_total_ok = 0;
    public $cms_total_failed = 0;

    /** 重新插入所有职位
     * @return bool
     */
    public function storeAllJob($request)
    {
        try {
            $this->cms_total = isset($request->cms_total) ? $request->cms_total : 0;
            $this->cms_total_ok = isset($request->cms_total_ok) ? $request->cms_total_ok : 0;
            $this->cms_total_failed = isset($request->cms_total_failed) ? $request->cms_total_failed : 0;
            $index = $this->index;
            $page = Paginator::resolveCurrentPage('page');
            $paginate = 1000;//每页条数
            // 宣布开始重建索引
            if ($page == 1) {
                $index->beginRebuild();
                $this->logXS("----------------------------------------------\n");
                $this->logXS("开始批量导入职位 \n");
            }

            //每次数据库读取取1000条,减少内存消耗,//审核通过的,公开的
            $jobs = DB::table('company_job as t1')
                ->join('company_basic as t2', 't1.com_id', '=', 't2.id')
                ->select(
                    't1.id', 't1.com_id', 't1.job_title', 't1.industry',
                    't1.job_category1', 't1.job_category2', 't1.job_category3', 't1.job_category4', 't1.job_category5',
                    't1.location1', 't1.location2', 't1.location3', 't1.location4', 't1.location5',
                    't1.recruiting_num', 't1.salary_above', 't1.salary_below', 't1.description', 't1.welfare', 't1.part_status',
                    't1.education', 't1.work_year', 't1.age_above', 't1.age_below', 't1.gender', 't1.updatetime',
                    't2.profile',
                    't2.company_name', 't2.region', 't2.industry as company_industry', 't2.address', 't2.employee_num', 't1.urgent',
                    't2.longitude', 't2.latitude', 't2.famous', 't2.logo'
                )
                ->where('t1.job_status', '1')//职位显示审核通过的
                ->orderBy('t1.id')
                ->simplePaginate($paginate);
            $bl = count($jobs) > self::$OPEN_BUFFER_COUNT;//是否数量超过一定条数
            if ($bl) $index->openBuffer();//数量多则使用索引缓冲区
            $ids_arr = [];//需要把xs_status改为1的所有id
            foreach ($jobs as $job) {
                $ids_arr[] = $job->id;
                $this->cms_total++;
                try {
                    $doc = new XSDocument;
                    $doc->setFields($this->makeData($job)); // 用数组进行批量赋值
                    $index->update($doc); // 添加
                    $this->cms_total_ok++;
                } catch (XSException $e) {
                    $this->logXS("警告：添加第 $this->cms_total 条 id=$job->id 职位失败 - " . $e->getMessage() . "\n");
                    $this->logXS($e->getTraceAsString());
                    $this->cms_total_failed++;
                }
            }
            if ($bl) $index->closeBuffer();
            $ids_str = implode(',', $ids_arr);
            if ($page % 10 == 0) {
                $this->logXS("报告：累计已处理职位 $this->cms_total 条 ...成功 $this->cms_total_ok 条，失败 $this->cms_total_failed 条\n");
            }
            DB::table('company_job')->whereIn('id', $ids_arr)->update(['xs_status' => 1]);
            $result = [];
            $result['cms_total'] = $this->cms_total;
            $result['cms_total_ok'] = $this->cms_total_ok;
            $result['cms_total_failed'] = $this->cms_total_failed;
            $jobs_count = count($jobs);
            if ($jobs_count < $paginate) {
                if ($jobs_count > 0)
                    $this->logXS("报告：累计已处理职位 $this->cms_total 条 ...成功 $this->cms_total_ok 条，失败 $this->cms_total_failed 条\n");
                $this->logXS("完成职位导入!!!<br><br>\n");
                // 告诉服务器重建完毕
                $index->endRebuild();
                $result['result'] = '2';//说明是最后一页
            } else {
                $result['result'] = '1';
            }
            return $result;
        } catch (XSException $e) {
            //您还可以在重建前先调用 XSIndex::stopRebuild 直接清除这个错误状态
            $this->index->stopRebuild();
            $this->logXS('导入出错\n$e<br><br>');
            return ['result' => '0'];
        }
    }

    /**
     * 从mysql中查找一条对应的职位
     * @param $id   职位id
     * @return mixed
     */
    public function getFromMySql($id)
    {
        //搜索岗位列表
        $company_job = DB::table('company_job as t1')
            ->join('company_basic as t2', 't1.com_id', '=', 't2.id')
            //获取字段
            ->select(
                't1.id', 't1.com_id', 't1.job_title', 't1.industry',
                't1.job_category1', 't1.job_category2', 't1.job_category3', 't1.job_category4', 't1.job_category5',
                't1.location1', 't1.location2', 't1.location3', 't1.location4', 't1.location5',
                't1.recruiting_num', 't1.salary_above', 't1.salary_below', 't1.description', 't1.welfare', 't1.part_status',
                't1.education', 't1.work_year', 't1.age_above', 't1.age_below', 't1.gender', 't1.updatetime',
                't2.profile',
                't2.company_name', 't2.region', 't2.industry as company_industry', 't2.address', 't2.employee_num', 't1.urgent',
                't2.longitude', 't2.latitude', 't2.famous', 't2.logo'
            )
            //指定了职位id
            ->whereIn('t1.id', $id)
            //职位显示审核通过的
            ->where('t1.job_status', '1')
            ->get();
        return $company_job;
    }

    /** 搜索,注意:返回的结构是[data=>[...],total=>123],data数组里的才是数据
     *
     * $input的可以传入的键如下
     *
     *   键名             类型                     备注
     * salary         string                    月薪要求
     * release_date   int                       几天内更新过
     * anxious        int                       急招，则选的是5天内发布的
     * map_show       int                       根据定位查找，则选15天内更新的
     * age            int                       年龄范围
     * education      int                       学历
     * work_year      int                      工作经验及以上
     * longitude      float                     经度范围，0.05为5公里以内
     * latitude       float                     维度范围，0.05为5公里以内
     * updatetime     int                      最近更新 传入天数
     *
     * @param $input
     * @param int $perPage 一页个数
     * @param int $curPage 查询第几页,从1开始
     * @param bool|true $getTotal 是否获取总数,默认获取
     * @param bool|true $orderByTime 是否按照时间排序
     * @return array
     */
    public function searchJob($input, $curPage = 1, $perPage = 20, $getTotal = true, $orderByTime = true)
    {
        //创建搜索条件
        $query = $this->makeQueryWithInput($input);
        try {
            //制作搜索条件
            $search = $this->search->setQuery($query);

            //月薪要求
            if (!empty($input['salary'])) $search->addRange('salary_above', $input['salary_above'], $input['salary_below']);
            //发布日期
            if (!empty($input['release_date'])) $search->addRange('updatetime', strtotime("-" . $input['release_date'] . "day"), null);
            //急招
            if (!empty($input['anxious'])) $search->addRange('urgent', strtotime(' -5 day', time()), null);
            //附近工作只找15天内的
            if (!empty($input['map_show'])) $search->addRange('updatetime', strtotime(' -15 day', time()), null);
            //年龄要求 当前所选大于或者等于年龄以上的
            if (!empty($input['age'])) {
                $search->addRange('age_above', null, $input['age']);
                $search->addRange('age_below', $input['age'], null);
            }
            //学历要求
            if (!empty($input['education'])) $search->addRange('education', null, $input['education']);
            //工作经验 当前所选工作经验以上
            if (!empty($input['work_year'])) $search->addRange('work_year', $input['work_year'], null);

            //排序
            if (!empty($input['map_show'])) {
                //根据定位排序
                $search->setGeodistSort(['longitude' => $input['longitude'], 'latitude' => $input['latitude']]);
            } elseif ($orderByTime) {
                $sorts = [];
                //按照更新时间排列
                if (array_key_exists('by_day', $input) && boolval($input['by_day'])) {
                    $sorts['updatetime_by_day'] = false;
                } else {
                    $sorts['updatetime'] = false;
                }
                $sorts['id_sort'] = false;
                $search->setMultiSort($sorts);
            }

            // 设置搜索语句, 分页, 偏移量
            $this->cms_curPage = $curPage;
            $this->cms_perPage = $perPage;
            $search->setLimit($getTotal ? $perPage : $perPage + 1, $perPage * ($curPage - 1));
            //执行搜索，将搜索结果文档保存在 $results 数组中
            $results = $search->search();
            $total = 0;//获取搜索结果的匹配总数估算值
            if ($getTotal) $total = $search->count();

            $data = [];//返回结果的数据重组
            foreach ($results as $result) {
                $item = (object)$result->getFields();//将xs对象转为php普通对象(stdClass)
                //去掉不该输出的2数据
                unset($item->other_important);
                unset($item->other);
                if ($item->age_below == 99) {
                    $item->age_below = 0;
                }
                //处理location1~location5工作地区
                $locationArr = self::explodeManyCidAndPid($result->location, 'location');
                foreach ($locationArr as $k => $v) {
                    $item->$k = $v;
                }
                //格式化更新时间
                $item->updatetime = date('Y-m-d', $item->updatetime);
                //格式化急聘时间
                $item->urgent = date('Y-m-d H:i:s', $item->urgent);
                //计算距离
                if (!empty($input['map_show'])) {
                    $item->juli = self::GetDistance($item->latitude, $item->longitude, $input['latitude'], $input['longitude']);
                }
                $data[] = $item;
            }
            return ['data' => $data, 'total' => $total];
        } catch (XSException $e) {
            return ['data' => [], 'total' => 0];
        }
    }

    /**
     * 把mysql的数据转成xunsearch对应的格式
     * @param $value
     * @return array
     */
    public function makeData($value)
    {
        $other = $value->profile;//公司简介
        $other_important = $value->description;//职位描述
        $location = self::implodeManyCidAndPid($value, 'location');
        $job_category = self::implodeCid($value, 'job_category');
        $data = [];
        $data['id'] = $value->id;//职位id
        $data['id_sort'] = $value->id;//职位id
        $data['job_title'] = $value->job_title;//职位名称
        $data['other'] = $other;//职位次要搜索内容
        $data['other_important'] = $other_important;//职位主要搜索内容
        $data['location'] = $location;//工作地点5个空格隔开
        $data['welfare'] = $value->welfare;//福利
        $data['salary_above'] = $value->salary_above;//薪资待遇>
        $data['salary_below'] = $value->salary_below;//薪资待遇<
        $data['job_category'] = $job_category;//岗位类别5个空格隔开
        $data['industry'] = $value->industry;//所属行业
        $data['work_year'] = $value->work_year;//工作经验
        $data['age_above'] = $value->age_above;//年龄要求>
        $data['age_below'] = $value->age_below == 0 ? 99 : $value->age_below;//年龄要求<
        $data['education'] = $value->education;//学历
        $data['urgent'] = (is_null($value->urgent) || $value->urgent == '0000-00-00 00:00:00') ? 0 : strtotime($value->urgent);//急招，紧急截止时间
        $data['part_status'] = $value->part_status;//兼职状态(1全职 2实习 3兼职 4临时)
        $data['updatetime'] = (is_null($value->updatetime) || $value->updatetime == '0000-00-00 00:00:00') ? 0 : strtotime($value->updatetime);//更新时间
        $data['updatetime_by_day'] = (is_null($value->updatetime) || $value->updatetime == '0000-00-00 00:00:00') ? 0 : strtotime(substr($value->updatetime, 0, 10) . ' 00:00:00');//更新时间
        $data['com_id'] = $value->com_id;//公司id
        $data['company_name'] = $value->company_name;//公司名称
        $data['company_industry'] = $value->company_industry;//所属行业
        $data['employee_num'] = $value->employee_num;//员工数量
        $data['longitude'] = $value->longitude ? $value->longitude : 0;//坐标经度
        $data['latitude'] = $value->latitude ? $value->latitude : 0;//坐标纬度
        $data['famous'] = $value->famous;//知名企业
        $data['logo'] = $value->logo;//知名企业
//        dd($data);
        return $data;
    }

    public function makeQueryWithInput($input)
    {
        $query = '';
        if (empty($input)) return $query;

        //工作岗位cid转为中文名,全文检索
        if (!empty($input['jobsort'])) {
            $query .= self::jobSortToQuery($input['jobsort']);
        }

        //工作 地区选择

        if (!empty($input['jobarea'])) {
            $query .= self::jobAreaToQuery($input['jobarea']);
        }

        //指定搜索的key
        /**jobarea:福利,sex:性别要求,part_status:实习**/
        $selfKey = ['welfare', 'sex', 'part_status'];
        foreach ($selfKey as $key) {
            if (empty($input[$key])) continue;
            $query .= "$key:$input[$key] ";
        }

        //关键字(全文搜索,如果多个关键字OR连接)
        if (!empty($input['keyword'])) {
            $values = $input['keyword'];
            //不是数组,转为数组
            $values = is_array($values) ? $values : explode(',', $values);
            $query .= implode(' OR ', $values) . ' ';
        }

        //公司名名字搜索
        if (!empty($input['company_name'])) {
            $key = !empty($input['keyword']) ? 'OR company_name:' : 'company_name:';
            $query .= $key . $input['company_name'] . ' ';
        }

        //意向搜索
        if (!empty($input['job_title'])) {
            $key = !empty($input['keyword']) ? 'OR job_title:' : 'job_title:';
            $query .= $key . $input['job_title'] . ' ';
        }

        //所属行业
        if (!empty($input['industry'])) {
            $values = $input['industry'];
            //不是数组,转为数组
            $values = is_array($values) ? $values : explode(',', $values);
            foreach ($values as $item) {
                $industry[] = "industry:$item";
            }
            $query .= '(' . implode(' OR ', array_unique($industry)) . ') ';
        }

        return rtrim($query);
    }

    /** 每分钟的定时执行代码
     * @return bool
     */
    public static function timerUpdate()
    {
        $xs = new JobXS();
        try {
            $xs->logXSDaily('正在执行定时更新职位...');
            $index = $xs->index;

            $addCount = 0;//插入个数
            $deleteCount = 0;//删除个数

            //更新
            //每次数据库读取取1000条,减少内存消耗,//审核通过的,公开的
            DB::table('company_job as t1')
                ->join('company_basic as t2', 't1.com_id', '=', 't2.id')
                ->select(
                    't1.id', 't1.com_id', 't1.job_title', 't1.industry',
                    't1.job_category1', 't1.job_category2', 't1.job_category3', 't1.job_category4', 't1.job_category5',
                    't1.location1', 't1.location2', 't1.location3', 't1.location4', 't1.location5',
                    't1.recruiting_num', 't1.salary_above', 't1.salary_below', 't1.description', 't1.welfare', 't1.part_status',
                    't1.education', 't1.work_year', 't1.age_above', 't1.age_below', 't1.gender', 't1.updatetime',
                    't2.profile',
                    't2.company_name', 't2.region', 't2.industry as company_industry', 't2.address', 't2.employee_num', 't1.urgent',
                    't2.longitude', 't2.latitude', 't2.famous', 't2.logo'
                )
                ->where('t1.job_status', 1)//职位显示审核通过的
                ->where('t1.xs_status', 0)//需要被同步到xunsearch
                ->chunk(1000, function ($jobs) use ($index, $xs, &$addCount) {
                    $bl = count($jobs) > self::$OPEN_BUFFER_COUNT;
                    if ($bl) $index->openBuffer();
                    foreach ($jobs as $job) {
                        try {
                            $doc = new XSDocument;
                            $doc->setFields($xs->makeData($job)); // 用数组进行批量赋值
                            $index->update($doc); // 添加
                            ++$addCount;
                            DB::table('company_job')->where('id',$job->id)->update(['xs_status' => 1]);
                        } catch (XSException $e) {
                            $xs->logXSDaily("id=$job->id 职位添加失败 - " . $e->getMessage());
                        }
                    }
                    if ($bl) $index->closeBuffer();
                });

            $xs->logXSDaily("成功更新了 $addCount 条职位");

            //删除
            $ids = DB::table('company_job')
                ->select(['id', 'xs_status'])
                ->where('job_status', '!=', 1)
                ->where('xs_status', 0)//需要被同步到xunsearch
                ->pluck('id');

            foreach ($ids as $id) {
                try {
                    $index->del($id);
                    DB::table('company_job')->where('id', $id)->update(['xs_status' => 1]);
                    $xs->logXSDaily('id='.$id.'职位删除成功');
                    $deleteCount += 1;
                } catch (XSException $e) {
                    $xs->logXSDaily("id=$id 职位删除失败 - " . $e->getMessage());
                }
            }

            $xs->logXSDaily("成功删除了 $deleteCount 条职位");

            //强制刷新迅搜
            $index->flushIndex();
            return true;
        } catch (XSException $e) {
            $xs->logXSDaily("执行出错:" . $e);
            return false;
        }
    }
}
